/**
 * Copyright (c) 2019 xstgongyi.org
 * All rights reserved.
 */
package org.xstgongyi.eduaid.service;

import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.xstgongyi.eduaid.bo.StudentCurrentAidStatus;
import org.xstgongyi.eduaid.common.PageHelper;
import org.xstgongyi.eduaid.dao.StudentBankAccountMapper;
import org.xstgongyi.eduaid.dataobject.*;
import org.xstgongyi.eduaid.manager.ProjectManager;
import org.xstgongyi.eduaid.manager.SchoolYearManager;
import org.xstgongyi.eduaid.manager.SemesterManager;
import org.xstgongyi.eduaid.manager.StudentManager;

import java.io.FileOutputStream;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author oldcrane<br               />
 * @created 2019-04-11
 */
@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentManager studentManager;

    @Autowired
    private StudentBankAccountMapper studentBankAccountDao;

    @Autowired
    private ProjectManager projectManager;

    @Autowired
    private SemesterManager semesterManager;

    @Autowired
    private SchoolYearManager schoolYearManager;

    @Autowired
    private StudentAidService aidService;

    @Override
    @Transactional
    public void insertBankAccount(StudentBankAccountDO bankAccount) {
        // 检查该学生是否已存在active的银行账户，如果存在，需要先禁用。
        disableExistingBankAccount(bankAccount.getStudentId());

        realInsertBankAccount(bankAccount);
        linkBankAccount(bankAccount.getStudentId(), bankAccount.getId());
    }

    @Override
    @Transactional
    public void updateBankAccount(StudentBankAccountDO bankAccount) {
        int bankAccountId = bankAccount.getId();
        StudentBankAccountDO accountFromDb = studentBankAccountDao.getById(bankAccountId);

        // TODO 检查输入参数中的studentId和从数据库去除的studentId是否一致

        if (accountFromDb.getUsed()) {
            disableBankAccount(accountFromDb);
            realInsertBankAccount(bankAccount);
            linkBankAccount(bankAccount.getStudentId(), bankAccount.getId());

        } else {
            accountFromDb.setName(bankAccount.getName());
            accountFromDb.setNumber(bankAccount.getNumber());
            accountFromDb.setBank(bankAccount.getBank());
            accountFromDb.setRelation(bankAccount.getRelation());
            accountFromDb.setGmtUpdated(LocalDateTime.now());
            studentBankAccountDao.update(accountFromDb);
        }

    }

    // TODO 考虑增加manager层
    private boolean realInsertBankAccount(StudentBankAccountDO bankAccount) {
        bankAccount.setActive(true); // 新建银行账号，必然为学生的当前使用账号
        bankAccount.setUsed(false); // 新建银行账号，设置为未使用
        LocalDateTime now = LocalDateTime.now();
        bankAccount.setGmtCreated(now);
        bankAccount.setGmtUpdated(now);
        int num = studentBankAccountDao.insert(bankAccount);
        return (1 == num);
    }

    // TODO 考虑增加manager层
    private boolean disableBankAccount(StudentBankAccountDO bankAccount) {
        bankAccount.setActive(false);
        bankAccount.setGmtUpdated(LocalDateTime.now());
        int num = studentBankAccountDao.update(bankAccount);
        return (1 == num);
    }

    // TODO 考虑增加manager层
    private boolean linkBankAccount(int studentId, int bankAccountId) {
        StudentDO student = studentManager.getById(studentId);
        // TODO check if the student exists
        student.setBankAccountId(bankAccountId);
        student.setGmtUpdated(LocalDateTime.now());
        int num = studentManager.update(student);
        return (1 == num);
    }

    private void disableExistingBankAccount(Integer studentId) {
        StudentDO student = this.getStudentById(studentId);
        if (null != student.getBankAccountId()) {
            StudentBankAccountDO bankAccount = this.getBankAccountById(student.getBankAccountId());
            bankAccount.setActive(false);
            this.updateBankAccount(bankAccount);
        }
    }

    @Override
    public StudentBankAccountDO getBankAccountById(int bankAccountId) {
        return studentBankAccountDao.getById(bankAccountId);
    }

    /**
     * 登记新学生，同时创建资助跟踪记录
     */
    @Override
    @Transactional
    public void insertStudent(StudentDO student) {
        String sn = genStudentSerialNumber(student.getProjectId(), student.getRegSemesterId());
        student.setSn(sn);
        student.setStatus(StudentCurrentAidStatus.funding.toString()); // 录入系统的学生信息，一般缺省为已确认要资助
        LocalDateTime now = LocalDateTime.now();
        student.setGmtCreated(now);
        student.setGmtUpdated(now);
        studentManager.insert(student);

        // 为新学生创建资助跟踪记录
        aidService.insertAidForNewStudent(student);

    }

    private String genStudentSerialNumber(Integer projectId, Integer semesterId) {
        ProjectDO project = projectManager.getById(projectId);
        SemesterDO semester = semesterManager.getById(semesterId);
        SchoolYearDO schoolYear = schoolYearManager.getById(semester.getSchoolYearId());
        String snPrefix = project.getPrefix() + schoolYear.getAbbrev();

        String maxSn = studentManager.getMaxSn(snPrefix + "%");
        String sn;
        if (null == maxSn || maxSn.isEmpty()) {
            sn = snPrefix + "001";
        } else {
            String maxNumStr = maxSn.substring(snPrefix.length());
            int maxNum = Integer.parseInt(maxNumStr) + 1;
            sn = snPrefix + String.format("%03d", maxNum);
        }
        return sn;
    }

    @Override
    public void updateStudent(StudentDO student) {
        StudentDO objInDB = studentManager.getById(student.getId());

        // 前端可能只提供部分字段，需要用已有的数据进行填充
        Integer oldProjectId = objInDB.getProjectId();
        Integer oldRegSemesterId = objInDB.getRegSemesterId();
        if (student.getProjectId() != null) {
            objInDB.setProjectId(student.getProjectId());
        }
        if (student.getRegSemesterId() != null) {
            objInDB.setRegSemesterId(student.getRegSemesterId());
        }
        if (student.getSn() != null) {
            objInDB.setSn(student.getSn());
        } else if (!oldProjectId.equals(objInDB.getProjectId())
                || !oldRegSemesterId.equals(objInDB.getRegSemesterId())) {
            objInDB.setSn(genStudentSerialNumber(objInDB.getProjectId(), objInDB.getRegSemesterId()));
        }

        if (student.getName() != null) {
            objInDB.setName(student.getName());
        }
        if (student.getGender() != null) {
            objInDB.setGender(student.getGender());
        }
        if (student.getIdNumber() != null) {
            objInDB.setIdNumber(student.getIdNumber());
        }
        if (student.getRegSchool() != null) {
            objInDB.setRegSchool(student.getRegSchool());
        }
        if (student.getRegGradeId() != null) {
            objInDB.setRegGradeId(student.getRegGradeId());
        }
        if (student.getContactPhone() != null) {
            objInDB.setContactPhone(student.getContactPhone());
        }
        if (student.getContactWechat() != null) {
            objInDB.setContactWechat(student.getContactWechat());
        }
        if (student.getContactEmail() != null) {
            objInDB.setContactEmail(student.getContactEmail());
        }
        if (student.getContactOther() != null) {
            objInDB.setContactOther(student.getContactOther());
        }
        if (student.getDescription() != null) {
            objInDB.setDescription(student.getDescription());
        }

        objInDB.setGmtUpdated(LocalDateTime.now());
        studentManager.update(objInDB);
    }

    @Override
    public StudentDO getStudentById(Integer studentId) {
        return studentManager.getById(studentId);
    }

    @Override
    public List<StudentDO> listByProject(int projectId) {
        return studentManager.listByProject(projectId);
    }

    @Override
    public List<StudentDO> listAll() {
        return studentManager.listAll();
    }

    @Override
    public List<StudentDO> listPage(int pageNumber, int pageSize, int projectId, String status, String keyword) {
        Map<String, Object> condition = new HashMap<>();
        pageNumber = pageNumber > 0 ? pageNumber : 1; // 缺省为第一页
        pageSize = pageSize > 0 ? pageSize : 20; // 缺省一页20条记录
        int offset = PageHelper.calcOffset(pageNumber, pageSize);
        condition.put("offset", offset);
        condition.put("limit", pageSize);
        if (projectId > 0) {
            condition.put("projectId", projectId);
        }
        if (!StringUtils.isEmpty(status)) {
            condition.put("status", status);
        }
        if (!StringUtils.isEmpty(keyword)) {
            condition.put("keyword", "%" + keyword + "%");
        }

        List<StudentDO> students = studentManager.listPage(condition);
        return students;
    }

    @Override
    public int countTotal(int projectId, String status, String keyword) {
        Map<String, Object> condition = new HashMap<>();
        if (projectId > 0) {
            condition.put("projectId", projectId);
        }
        if (!StringUtils.isEmpty(status)) {
            condition.put("status", status);
        }
        if (!StringUtils.isEmpty(keyword)) {
            condition.put("keyword", "%" + keyword + "%");
        }
        return studentManager.countTotal(condition);
    }

    public String exportStudentPDF(Integer studentId) {

        StudentDO student = studentManager.getById(studentId);
        Integer projectID = student.getProjectId();
        ProjectDO project = projectManager.getById(projectID);

        // 导出信息
        String fileName = "/tmp/" + student.getSn() + "_" + student.getName() + ".pdf";
        String title = project.getName() + "-" + student.getName() + "调研日记";
        String recommend = "小石头公益建议资助标准:" + student.getSuggestAmount() + "元/年";

        try {
            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            Font FontChinese = new Font(bfChinese, 12, Font.NORMAL);
            Document doc = new Document();
            PdfWriter.getInstance(doc, new FileOutputStream(fileName));
            doc.open();
            doc.add(new Paragraph(title, FontChinese));
            doc.add(new Paragraph(recommend, FontChinese));
            doc.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return fileName;

    }

}
